import 'dart:convert';

import 'package:backend.core/core/infrastructure/helpers/request_helpers.dart';
import 'package:backend.core/logger/logger.dart';
import 'package:backend.purchases/domain/entities/google_play_api/google_play_api_notification.dart';
import 'package:backend.purchases/domain/entities/google_play_api/google_play_api_purchased_item_identifier.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_canceled_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_deferred_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_expired_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_in_grace_period_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_on_hold_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_pause_schedule_changed_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_paused_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_price_change_confirmed_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_recovered_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_renewed_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_restarted_google_play_api_notification/use_case.dart';
import 'package:backend.purchases/domain/use_cases/google_play_api_notification_use_cases/handle_subscription_revoked_google_play_api_notification/use_case.dart';
import 'package:equatable/equatable.dart';
import 'package:shelf/shelf.dart';

part 'dtos/notification_dto.dart';

part 'dtos/notification_dto_factory.dart';

part 'dtos/one_time_purchase_item_notification_data_dto.dart';

part 'dtos/subscription_notification_data_dto.dart';

part 'dtos/test_notification_data_dto.dart';

final _jsonBase64 = json.fuse(utf8.fuse(base64Url));

abstract class GooglePlayApiNotificationController {
  Future<Response> call(Request request);
}

class GooglePlayApiNotificationControllerImpl implements GooglePlayApiNotificationController {
  const GooglePlayApiNotificationControllerImpl({
    required HandleSubscriptionCanceledGooglePlayApiNotification
        handleSubscriptionCanceledGooglePlayApiNotification,
    required HandleSubscriptionDeferredGooglePlayApiNotification
        handleSubscriptionDeferredGooglePlayApiNotification,
    required HandleSubscriptionExpiredGooglePlayApiNotification
        handleSubscriptionExpiredGooglePlayApiNotification,
    required HandleSubscriptionInGracePeriodGooglePlayApiNotification
        handleSubscriptionInGracePeriodGooglePlayApiNotification,
    required HandleSubscriptionOnHoldGooglePlayApiNotification
        handleSubscriptionOnHoldGooglePlayApiNotification,
    required HandleSubscriptionPauseScheduleChangedGooglePlayApiNotification
        handleSubscriptionPauseScheduleChangedGooglePlayApiNotification,
    required HandleSubscriptionPausedGooglePlayApiNotification
        handleSubscriptionPausedGooglePlayApiNotification,
    required HandleSubscriptionPriceChangeConfirmedGooglePlayApiNotification
        handleSubscriptionPriceChangeConfirmedGooglePlayApiNotification,
    required HandleSubscriptionRecoveredGooglePlayApiNotification
        handleSubscriptionRecoveredGooglePlayApiNotification,
    required HandleSubscriptionRenewedGooglePlayApiNotification
        handleSubscriptionRenewedGooglePlayApiNotification,
    required HandleSubscriptionRestartedGooglePlayApiNotification
        handleSubscriptionRestartedGooglePlayApiNotification,
    required HandleSubscriptionRevokedGooglePlayApiNotification
        handleSubscriptionRevokedGooglePlayApiNotification,
  })  : _handleSubscriptionCanceledGooglePlayApiNotification =
            handleSubscriptionCanceledGooglePlayApiNotification,
        _handleSubscriptionDeferredGooglePlayApiNotification =
            handleSubscriptionDeferredGooglePlayApiNotification,
        _handleSubscriptionExpiredGooglePlayApiNotification =
            handleSubscriptionExpiredGooglePlayApiNotification,
        _handleSubscriptionInGracePeriodGooglePlayApiNotification =
            handleSubscriptionInGracePeriodGooglePlayApiNotification,
        _handleSubscriptionOnHoldGooglePlayApiNotification =
            handleSubscriptionOnHoldGooglePlayApiNotification,
        _handleSubscriptionPauseScheduleChangedGooglePlayApiNotification =
            handleSubscriptionPauseScheduleChangedGooglePlayApiNotification,
        _handleSubscriptionPausedGooglePlayApiNotification =
            handleSubscriptionPausedGooglePlayApiNotification,
        _handleSubscriptionPriceChangeConfirmedGooglePlayApiNotification =
            handleSubscriptionPriceChangeConfirmedGooglePlayApiNotification,
        _handleSubscriptionRecoveredGooglePlayApiNotification =
            handleSubscriptionRecoveredGooglePlayApiNotification,
        _handleSubscriptionRenewedGooglePlayApiNotification =
            handleSubscriptionRenewedGooglePlayApiNotification,
        _handleSubscriptionRestartedGooglePlayApiNotification =
            handleSubscriptionRestartedGooglePlayApiNotification,
        _handleSubscriptionRevokedGooglePlayApiNotification =
            handleSubscriptionRevokedGooglePlayApiNotification;

  final HandleSubscriptionCanceledGooglePlayApiNotification
      _handleSubscriptionCanceledGooglePlayApiNotification;
  final HandleSubscriptionDeferredGooglePlayApiNotification
      _handleSubscriptionDeferredGooglePlayApiNotification;
  final HandleSubscriptionExpiredGooglePlayApiNotification
      _handleSubscriptionExpiredGooglePlayApiNotification;
  final HandleSubscriptionInGracePeriodGooglePlayApiNotification
      _handleSubscriptionInGracePeriodGooglePlayApiNotification;
  final HandleSubscriptionOnHoldGooglePlayApiNotification
      _handleSubscriptionOnHoldGooglePlayApiNotification;
  final HandleSubscriptionPauseScheduleChangedGooglePlayApiNotification
      _handleSubscriptionPauseScheduleChangedGooglePlayApiNotification;
  final HandleSubscriptionPausedGooglePlayApiNotification
      _handleSubscriptionPausedGooglePlayApiNotification;
  final HandleSubscriptionPriceChangeConfirmedGooglePlayApiNotification
      _handleSubscriptionPriceChangeConfirmedGooglePlayApiNotification;
  final HandleSubscriptionRecoveredGooglePlayApiNotification
      _handleSubscriptionRecoveredGooglePlayApiNotification;
  final HandleSubscriptionRenewedGooglePlayApiNotification
      _handleSubscriptionRenewedGooglePlayApiNotification;
  final HandleSubscriptionRestartedGooglePlayApiNotification
      _handleSubscriptionRestartedGooglePlayApiNotification;
  final HandleSubscriptionRevokedGooglePlayApiNotification
      _handleSubscriptionRevokedGooglePlayApiNotification;

  @override
  Future<Response> call(Request request) async {
    final requestBody = await parseJsonRequestBody(
      request: request,
    );

    final message = requestBody['message'] as Map<String, dynamic>;
    final data = message['data'] as String;
    final notificationJson = _jsonBase64.decode(data) as Map<String, dynamic>;
    final _NotificationDataDto notificationDataDto;

    try {
      notificationDataDto = _NotificationDtoFactory().fromJson(notificationJson);
    } catch (e, s) {
      Logger().w(null, e, s);
      return Response(400);
    }

    final notificationData = notificationDataDto.toEntity();

    if (notificationData is GooglePlayApiTestNotificationData) {
      return Response(200);
    }

    if (notificationData is GooglePlayApiOneTimePurchaseItemNotificationData) {
      Logger().i('Google Play Notification: one time purchase item');
      return Response(200);
    }

    if (notificationData is GooglePlayApiSubscriptionNotificationData) {
      final notificationType = notificationData.type;

      Logger().i('Google Play Notification: subscription [${notificationType.toString().split('.').last}]');

      final purchasedItemIdentifier = GooglePlayApiPurchasedItemIdentifier(
        purchaseToken: notificationData.purchaseToken,
        purchaseItemSku: notificationData.purchaseItemSku,
      );

      if (notificationType == GooglePlayApiSubscriptionNotificationType.purchased) {
        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.recovered) {
        final failureOrSuccess = await _handleSubscriptionRecoveredGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.renewed) {
        final failureOrSuccess = await _handleSubscriptionRenewedGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.canceled) {
        final failureOrSuccess = await _handleSubscriptionCanceledGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.onHold) {
        final failureOrSuccess = await _handleSubscriptionOnHoldGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.inGracePeriod) {
        final failureOrSuccess = await _handleSubscriptionInGracePeriodGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.restarted) {
        final failureOrSuccess = await _handleSubscriptionRestartedGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.priceChangeConfirmed) {
        final failureOrSuccess =
            await _handleSubscriptionPriceChangeConfirmedGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.deferred) {
        final failureOrSuccess = await _handleSubscriptionDeferredGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.paused) {
        final failureOrSuccess = await _handleSubscriptionPausedGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.pauseScheduleChanged) {
        final failureOrSuccess =
            await _handleSubscriptionPauseScheduleChangedGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.revoked) {
        final failureOrSuccess = await _handleSubscriptionRevokedGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }

      if (notificationType == GooglePlayApiSubscriptionNotificationType.expired) {
        final failureOrSuccess = await _handleSubscriptionExpiredGooglePlayApiNotification(
          purchasedItemIdentifier: purchasedItemIdentifier,
        );

        if (failureOrSuccess.isLeft()) {
          return Response(500);
        }

        return Response(200);
      }
    }

    throw UnimplementedError();
  }
}
